/**
 * 210824：升级修改【three.js r120-r131】
 */
let THREE=require('three');
import SelectConfig from "./select-config";
import GeometryUtils from "../general/geometry-utils";

/**
 * 投影几何体
 */
class SelectGeometry{
    constructor(){
        this.vertices=null;
        this.faces=null;
        this.lines=null;
        this.maxX=Number.NEGATIVE_INFINITY;
        this.maxY=Number.NEGATIVE_INFINITY;
        this.minX=Number.POSITIVE_INFINITY;
        this.minY=Number.POSITIVE_INFINITY;
    }
    set vCount(length){
        this.vertices=new Float32Array(length);
    }
    vertex(index,out){
        out.x=this.vertices[index*2];
        out.y=this.vertices[index*2+1];
    }
    set fCount(length){
        this.faces=new Uint16Array(length);
    }
    set lCount(length){
        this.lines=new Uint16Array(length);
    }
    reset(){
        this.vertices=null;
        this.faces=null;
        this.lines=null;
        this.maxX=Number.NEGATIVE_INFINITY;
        this.maxY=Number.NEGATIVE_INFINITY;
        this.minX=Number.POSITIVE_INFINITY;
        this.minY=Number.POSITIVE_INFINITY;
    }
    dispose(){
        this.vertices=null;
        this.faces=null;
        this.lines=null;
        this.maxX=null;
        this.maxY=null;
        this.minX=null;
        this.minY=null;
    }
}

/**
 * 选取mesh的配置
 */
export default class SelectMeshConfig extends SelectConfig{
    constructor(values){
        super(values);
        console.warn('this class is deprecated now ,use new SelectMeshConfig which also support XR!');
    }
    get type(){
        return 'SelectMeshConfig';
    }
    checkType(object){
        return object instanceof THREE.Mesh;
    }
    compare(a, b) {
        return a.uuid===b.uuid;
    }
    intersectRect(object,pointer1,pointer2,camera,rect){
        if(!object.visible)return false;
        let box=this._tB0;
        GeometryUtils.make2DAABB(pointer1.x,pointer2.x,pointer1.y,pointer2.y,box,false);
        box.min.z=-0.1;
        box.max.z=0.1;
        return this.checkProjectionGeometry(object,box,camera,rect);
    }
    checkProjectionGeometry(object,box,camera,rect){
        this._projectGeometry(object,this._projGeometry,camera,rect);
        let objectRect=this._tB1;
        GeometryUtils.make2DAABB(this._projGeometry.minX,this._projGeometry.maxX,this._projGeometry.minY,this._projGeometry.maxY,objectRect,true);
        objectRect.min.z=-0.1;
        objectRect.max.z=0.1;
        if (!box.intersectsBox(objectRect)){
            return false;
        }
        for (let i=0;i<this._projGeometry.vertices.length/2;i++) {
            this._projGeometry.vertex(i,this._tV1);
            if (box.containsPoint(this._tV1)){
                return true;
            }
        }
        for (let j =0;j<this._projGeometry.lines.length/2;j++) {
            this._projGeometry.vertex(this._projGeometry.lines[j*2],this._tV0);
            this._projGeometry.vertex(this._projGeometry.lines[j*2+1],this._tV1);
            if (GeometryUtils.lineIntersectsBox(this._tV0,this._tV1,box,2,true)){
                return true;
            }
        }
        let rectPoint = new THREE.Vector2(box.max.x, box.max.y);
        for (let i =0;i< this._projGeometry.faces.length/3;i++) {
            this._projGeometry.vertex(this._projGeometry.faces[i*3],this._tV0);
            this._projGeometry.vertex(this._projGeometry.faces[i*3+1],this._tV1);
            this._projGeometry.vertex(this._projGeometry.faces[i*3+2],this._tV2);
            if (GeometryUtils.ifPointInTriangle(this._tV0,this._tV1,this._tV2, rectPoint)){
                return true;
            }
        }
        return false;
    }
    intersectPointer(object,pointer,info,camera,rect){
        if(!object.visible)return false;
        let x = (pointer.x - rect.left) / rect.width;
        let y = (pointer.y - rect.top) / rect.height;
        this._tV0.set(x * 2 - 1, 1 - y * 2,0);
        this._rayCaster.setFromCamera(this._tV0, camera);
        return this._rayCaster.intersectObject(object, false,info);
    }
    dispose() {
        super.dispose();
        this._projGeometry.dispose();
        this._tV0=null;
        this._tV1=null;
        this._tV2=null;
        this._tB0=null;
        this._tB1=null;
        this._tV3=null;
        this._projGeometry=null;
        this._rayCaster=null;
    }

    _initVariable() {
        super._initVariable();
        this._tV0=new THREE.Vector3();
        this._tV1=new THREE.Vector3();
        this._tV2=new THREE.Vector3();
        this._tB0=new THREE.Box3();
        this._tB1=new THREE.Box3();
        this._tV3=new THREE.Vector3();
        this._projGeometry=new SelectGeometry();
        this._rayCaster=new THREE.Raycaster();
    }
    _projectGeometry(object,out,camera,rect){
        out.reset();
        let trsMatrix = object.matrixWorld;
        let halfWidth = rect.width / 2;
        let halfHeight = rect.height / 2;
        camera.updateMatrixWorld();

        if(object.geometry) {
            if (object.geometry instanceof THREE.BufferGeometry) {
                let ps = object.geometry.getAttribute('position').array;
                let range = object.geometry.drawRange;
                let count = range.count === Number.POSITIVE_INFINITY ? ps.length : range.count;
                out.vCount = count;
                for (let i = 0; i < count; i += 2) {
                    this._tV3.set(ps[i + range.start], ps[i + 1 + range.start], ps[i + 2 + range.start]);
                    this._tV3.applyMatrix4(trsMatrix).project(camera);
                    let x = (this._tV3.x * halfWidth) + halfWidth + rect.left;
                    let y = -(this._tV3.y * halfHeight) + halfHeight + rect.top;

                    if(out.maxX<x)out.maxX=x;
                    if(out.maxY<y)out.maxY=y;
                    if(out.minX>x)out.minX=x;
                    if(out.minY>y)out.minY=y;

                    out.vertices[i] = x;
                    out.vertices[i + 1] = y;
                }

                if(object.isMesh) {
                    if (object.geometry.index) {
                        let indices = object.geometry.index.array;
                        out.fCount=indices.length;
                        for (let i = 0; i < indices.length; i ++) {
                            out.faces[i]=indices[i];
                        }
                    } else {
                        let ps = object.geometry.getAttribute('position').array;
                        out.fCount=ps.length;
                        for (let i = 0; i < ps.length; i ++) {
                            out.faces[i]=i;
                        }
                    }
                }
            }
            //20210824
            // else if (object.geometry instanceof THREE.Geometry) {
            //     for (let i = 0; i < object.geometry.vertices.length; i++) {
            //         this._tV3.copy(object.geometry.vertices[i]);
            //         this._tV3.applyMatrix4(trsMatrix).project(camera);
            //         let x = (this._tV3.x * halfWidth) + halfWidth + rect.left;
            //         let y = -(this._tV3.y * halfHeight) + halfHeight + rect.top;
            //
            //         if(out.maxX<x)out.maxX=x;
            //         if(out.maxY<y)out.maxY=y;
            //         if(out.minX>x)out.minX=x;
            //         if(out.minY>y)out.minY=y;
            //
            //         out.vertices[i * 2] = x;
            //         out.vertices[i * 2 + 1] = y;
            //     }
            //
            //     for(let i=0;i<object.geometry.faces.length;i++){
            //         let f=object.geometry.faces[i];
            //         out.faces[i*3]=f.a;
            //         out.faces[i*3+1]=f.b;
            //         out.faces[i*3+2]=f.c;
            //     }
            // }
        }

        if(out.faces===null){
            let vl=out.vertices.length/3;
            out.lCount=(vl-1)*2;
            for(let i=0;i<vl-1;i++){
                out.lines.push(i,i+1);
            }
        }else {
            let fl=out.faces.length/3;
            out.lCount=fl*6;
            for (let i=0;i<fl;i++) {
                let a = out.faces[i*3];
                let b = out.faces[i*3+1];
                let c = out.faces[i*3+2];
                out.lines[i*6]=a;
                out.lines[i*6+1]=b;
                out.lines[i*6+2]=b;
                out.lines[i*6+3]=c;
                out.lines[i*6+4]=c;
                out.lines[i*6+5]=a;
            }
        }
    }
}